#!/usr/bin/perl
use Cwd;

# version $Id: index.cgi 26 2009-12-20 14:05:58Z olivier.courtade@gmail.com $

my $accountneeded='admin';


print "Content-type: text/html\n\n";
# Are we authenticated yet ?
if (open (IN,"/usr/syno/synoman/webman/modules/authenticate.cgi|")) {
	$user=<IN>;
	chop($user);
	close(IN);
}
# if not admin or no user at all...no authentication...so, bye-bye
if ($user ne $accountneeded) {
	print "<HTML><HEAD><TITLE>Login Required</TITLE></HEAD><BODY>Please login as admin first, before using this webpage</BODY></HTML>\n";
	die;
}


print <<EndOfFile;
<html>
	<head>

	<!-- LIBS -->     
	<script type="text/javascript" src="/scripts/extjs/adapter/yui/yui-utilities.js"></script>     
	<script type="text/javascript" src="/scripts/extjs/adapter/yui/ext-yui-adapter.js"></script>     
	<!-- ENDLIBS -->
  	<script type="text/javascript" src="/scripts/extjs/ext-all.js"></script>
	<script type="text/javascript" src="/scripts/extjs/ext-all-debug.js"></script>  


EndOfFile

# get configuration status
# and language settings
if (open(IN,"/etc/synoinfo.conf")) {
	while (<IN>) {
		($key,$value)=/([^=]+)="([^"]+)"/;
		if ($key eq 'language') {
			# needed to get translation table
			if ($value ne 'def') {
				$lang=$value;
			} else {
				$_=$ENV{'HTTP_ACCEPT_LANGUAGE'};
				($lang)=/^([^,;]+)/;
			}
		} 
	}
	close(IN);
}

print "<!-- info: language set to \"".$lang."\" -->\n";

# load translations
$path=$0;
$path=~ s#/[^/]*$##;

print "<!-- info: path set to \"".$path."\" -->\n";


my $langfile=$path ."/lang/" .$lang;
my %translation;

if (open(IN,$langfile)) {
	while(<IN>) {
		if (!(/^#/)) {
			($key,$value)=/"([^"]+)"\s*,\s*"([^"]+)"/;
			$translation{$key}=$value;
		}
	}
	close(IN);
} else {
    $erreur = $!;
    print "<!-- info: unable to open ".$langfile."  due to ".$erreur."-->\n";
}

# translation subroutine
sub trans {
	local ($tt,$ret);
	$tt=@_[0];
	if ($translation{$tt}) {
		$ret=$translation{$tt};
	} else {
		$ret=$tt;
	}
	return $ret;
}

# json_cn.js part
print <<'EndOfFile';

<script type="text/javascript">

var JSON = function ()
{
	var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };
	var s = {
		'boolean': function (x) {
			return String(x);
		},
		
		'date':	function (x) {
	        function f(n) {
				// Format integers to have at least two digits.
	            return n < 10 ? '0' + n : n;
	        };
	        return '"' + x.getFullYear() + '-' +
	                f(x.getMonth() + 1) + '-' +
	                f(x.getDate()) + 'T' +
	                f(x.getHours()) + ':' +
	                f(x.getMinutes()) + ':' +
	                f(x.getSeconds()) + '"';
    	},
		'number': function (x) {
        	return isFinite(x) ? String(x) : "null";
    	},
		'object':function (x) {
	        var a = ['{'],  // The array holding the text fragments.
	            b,          // A boolean indicating that a comma is required.
	            k,          // The current key.
	            v;          // The current value.
	        function p(s) {
				// p accumulates text fragment pairs in an array. It inserts a comma before all
				// except the first fragment pair.
	            if (b) {
	                a.push(',');
	            }
	            a.push(JSON.stringify(k), ':', s);
	            b = true;
	        };
	        for (k in x) {
	            if (x.hasOwnProperty(k)) {
	                v = x[k];
	                switch (typeof v) {
	                case 'undefined':
	                case 'function':
	                case 'unknown':
	                    break;
	                case 'object':
	                    if (v) {
							/*
	                        if (typeof v.toJSONString === 'function') {
	                            p(v.toJSONString());
	                        }
	                        */
							p(JSON.stringify(v));
	                    } else {
	                        p("null");
	                    }
	                    break;
	                default:
	                    p(JSON.stringify(v));
	                }
	            }
	        }
        	a.push('}');
        	return a.join('');
    	},
		'array':function (x) {
	        var a = ['['],  // The array holding the text fragments.
	            b,          // A boolean indicating that a comma is required.
	            i,          // Loop counter.
	            l = x.length,
	            v;          // The value to be stringified.
	
	        function p(s) {
	            if (b) {
	                a.push(',');
	            }
	            a.push(s);
	            b = true;
	        };
	        for (i = 0; i < l; i += 1) {
	            v = x[i];
	            switch (typeof v) {
	            case 'undefined':
	            case 'function':
	            case 'unknown':
	                break;
	            case 'object':
	                if (v) {
	                    /*
                        if (typeof v.toJSONString === 'function') {
                            p(v.toJSONString());
                        }
                        */
						p(JSON.stringify(v));
	                } else {
	                    p("null");
	                }
	                break;
	            default:
	                p(JSON.stringify(v));
	            }
	        }
	        a.push(']');
	        return a.join('');
	    },
		'string': function (x) {
            if (/["\\\x00-\x1f]/.test(x)) {
                return '"' + x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                    var c = m[b];
                    if (c) {
                        return c;
                    }
                    c = b.charCodeAt();
                    return '\\u00' +
                        Math.floor(c / 16).toString(16) +
                        (c % 16).toString(16);
                }) + '"';
            }
            return '"' + x + '"';
        }	
	};
	return {
		copyright: '(c)2005 JSON.org',
        license: 'http://www.JSON.org/license.html',
        stringify: function (v) {
			//alert("typeof v:"+typeof v);
			var vType = typeof(v);
			if(vType === 'object')
			{
				if(v instanceof Date)
				{
					vType = 'date';
				}
				else if(v instanceof Array)
				{
					vType = 'array';
				}
			}
            var f = s[vType];
            if (f) {
                v = f(v);
                if (typeof v == 'string') {
                    return v;
                }
            }
            return null;
        },
        parse: function (text) {
			//alert("text == " + text);
            try {
                return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                        text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
                    eval('(' + text + ')');
            } catch (e) {
                return false;
            }
        }
    };
}();

EndOfFile

print 'var testurl="http://'.$ENV{SERVER_NAME}.':26180/"'."\n";
# add translation strings
print 'var ttlang="'.$lang.'";' ."\n";
print 'var ttPleaseWait="' .trans("Please Wait") .'";' ."\n";
print 'var ttOK="' .trans("Ok") .'";' ."\n";
print 'var ttCancel="' .trans("Cancel") .'";' ."\n";
print 'var ttYes="' .trans("Yes") .'";' ."\n";
print 'var ttNo="' .trans("No") .'";' ."\n";
print 'var ttSave="' .trans("Save") .'";' ."\n";
print 'var ttReset="' .trans("Reset") .'";' ."\n";
print 'var ttId="' .trans("Id") .'";' ."\n";
print 'var ttName="' .trans("Name") .'";' ."\n";
print 'var ttPath="' .trans("Path") .'";' ."\n";
print 'var ttReloadApache="' .trans("Reload Apache") .'";' ."\n";
print 'var ttToolTipApache="' .trans("Restart Apache for using last modifications") .'";' ."\n";
print 'var ttBackupFiles="' .trans("Backup files") .'";' ."\n";
print 'var tttotal="' .trans("total") .'";' ."\n";
print 'var ttCurrentshows="' .trans("Current shows") .'";' ."\n";
print 'var ttresultsfound="' .trans("results found") .'";' ."\n";
print 'var ttnoresulttodisplay="' .trans("not result to display") .'";' ."\n";
print 'var ttAdd="' .trans("Add") .'";' ."\n";
print 'var ttDelete="' .trans("Delete") .'";' ."\n";
print 'var ttMessageTitle="' .trans("Message") .'";' ."\n";
print 'var ttconfirmreloadapache="' .trans("Do you really want to reload apache") .'";' ."\n";
print 'var ttReloadingApache="' .trans("Reloading apache") .'";' ."\n";
print 'var ttReloadingApacheError="' .trans("Unable to reload apache at this time") .'";' ."\n";
print 'var tttryagainlater="' .trans("Please try again later") .'";' ."\n";
print 'var ttconfirmbackupfiles="' .trans("Do you really want to do a backup of actual php.ini and synoneuf config files") .'";' ."\n";
print 'var ttBackupingfiles="' .trans("Backup files in progress") .'";' ."\n";
print 'var ttBackupingfilesError="' .trans("Unable to backup config files at this time") .'";' ."\n";
print 'var ttErrorTitle="' .trans("Error") .'";' ."\n";
print 'var ttconfirmitemtodelete="' .trans("Do you really want to delete them") .'";' ."\n";
print 'var ttselectonitemtodelete="' .trans("Please select at least one item to delete") .'";' ."\n";
print 'var ttunabletodeletepath="' .trans("Please select at least one item to delete") .'";' ."\n";
print 'var ttwaitcreatnewpath="' .trans("Wait while creating new path") .'";' ."\n";
print 'var tterrorformnewpath="' .trans("Please correct errors") .'";' ."\n";
print 'var tttitlecreatpath="' .trans("Create a new Path") .'";' ."\n";
print 'var ttpleasefillfields="' .trans("Please fill fields") .'";' ."\n";
print 'var Testtooltip="'.trans("Test the MediaCenter accessibility").'";' ."\n";
print 'var viewbutton="'.trans("View files and logs").'";' ."\n";




# handlerPathAction.js part
print <<'EndOfFile';

Ext.onReady(function(){
    var dialog;
	var myPageSize = 10;
    var fm = Ext.form, Ed = Ext.grid.GridEditor;
    Ext.QuickTips.init();
    function formatBoolean(value){
        return value ? "'" + ttYes + "'" : "'" + ttNo + "'";  
    }
    var cm = new Ext.grid.ColumnModel([{
           id: 'id',
           header: ttId ,
           dataIndex: 'id',
           width: 30,
           hidden: false
        },{
           header: ttName,
           dataIndex: 'name',
           width: 230
        },{
           header: ttPath,
           dataIndex: 'path',
           width: 230
        }
       ]);
    // by default columns are sortable
    cm.defaultSortable = false;
    // this could be inline, but we want to define the Newpath record
    // type so we can add records dynamically
    var NewAccount = Ext.data.Record.create([
           {name: 'id', type: 'string'},
           {name: 'name', type: 'string'},
           {name: 'path', type: 'string'}        
      ]);

   /************************************************************
    * connect to backend - grid - core part
    * create the Data Store
    *   connect with backend and list the result in page
    *   through JSON format
    ************************************************************/
    var ds = new Ext.data.Store({
        // load using script tags for cross domain, if the data in on the same domain as
        // this page, an HttpProxy would be better
        proxy: new Ext.data.ScriptTagProxy({

           url: 'listPath.cgi?action=listResult'
        }),

        // create reader that reads the Topic records
        reader: new Ext.data.JsonReader({
            root: 'results',
            totalProperty: 'totalCount',
            id: 'id'
        }, [
            {name: 'id'},
            {name: 'name'},
            {name: 'path'}
        ]),

        // turn on remote sorting
        remoteSort: true
    });
    ds.setDefaultSort('id', 'ASC');

    // create the editor grid
    var grid = new Ext.grid.EditorGrid('editor-grid', {
        ds: ds,
        cm: cm,
        //selModel: new Ext.grid.CellSelectionModel(),
        selModel: new Ext.grid.RowSelectionModel({singleSelect:true}),
        enableColLock:false
    });

    var layout = Ext.BorderLayout.create({
        center: {
            margins:{left:2,top:3,right:2,bottom:3},
            panels: [new Ext.GridPanel(grid)]
        }
    }, 'grid-panel');

    // render it
    grid.render();
    

   /************************************************************
    * create header panel 
    * add filter field - search function
    ************************************************************/
	var gridHead = grid.getView().getHeaderPanel(true);
	var tb = new Ext.Toolbar(gridHead);

    // add the detailed reloade apache button
    tb.add('-', {
        enableToggle:false,
        text: ttReloadApache,
        cls: '',
        tooltip: ttToolTipApache,
        handler: doReloadApache
    });  
    tb.add('-', {
        enableToggle:false,
        text: ttBackupFiles,
        cls: '',
        handler: dobackupfiles
    });
    
    tb.add('-', {
        icon: 'images/preview.png',
        cls: 'x-btn-text-icon',
        enableToggle:false,
        text: viewbutton,
        tooltip: viewbutton,
        handler: function (){
            location.href='view.cgi';
        }
    });
        
    tb.add('-', {
        icon: 'images/logo_sfr.jpg',
        cls: 'x-btn-text-icon',
        enableToggle:false,
        text: 'Test',
        tooltip: Testtooltip,
        handler: function (){
            var printPoWin = open(testurl);
        }
    });
    // --- end -- create foot panel   
    	
    
   /************************************************************
    * create footer panel 
    *    actions and paging
    ************************************************************/ 
    var gridFoot = grid.getView().getFooterPanel(true);

    // add a paging toolbar to the grid's footer
    var paging = new Ext.PagingToolbar(gridFoot, ds, {
        pageSize: myPageSize,
        displayInfo: true,
        displayMsg: tttotal + ' {2} ' + ttresultsfound + '. ' + ttCurrentshows + ' {0} - {1}',
        emptyMsg: ttnoresulttodisplay
    });
    // add the detailed add button
    paging.add('-', {
        enableToggle:false,
        text: ttAdd,
        cls: '',
        handler: doAdd
    });    
    // add the detailed delete button
    paging.add('-', {
        enableToggle:false,
        text: ttDelete,
        cls: '',
        handler: doDel
    });  

    // --- end -- create foot panel   

   /************************************************************
    * load parameter to backend 
    *    have beforelaod function
    ************************************************************/
	ds.on('beforeload', function() {
	  ds.baseParams = { // modify the baseParams setting for this request
	    
	  };
	});
    // trigger the data store load
    ds.load({params:{start:0, limit:myPageSize}});

    var conn = new Ext.data.Connection();

   /************************************************************
    * Action - doReloadApache
    *   start to handle doReloadApache function
    *   need confirm to doReloadApache
    ************************************************************/	
    function doReloadApache(){
       	Ext.MessageBox.confirm(ttMessageTitle, ttconfirmreloadapache + '?' , doReloadApache2);	
    }


    // History buton click handler. It submits the request and displays the response using history dialog
    function doReloadApache2(btn) {
        if(btn == 'yes') {
            action = "reloadapache";
            grid.getGridEl().mask(ttReloadingApache + '...');
            conn.request({
                url: 'listPath.cgi',
                method: 'GET',
                params: {"action": action,"lang": ttlang},
                success: function(responseObject) {
                    Ext.MessageBox.alert('Confirmation', responseObject.responseText);
                    grid.getGridEl().unmask(true);
                },
                failure: function() {
                    grid.getGridEl().unmask(true);
                    Ext.Msg.alert('Status', ttReloadingApacheError+'. '+tttryagainlater+'.');
                }
            });
        }
    }

   /************************************************************
    * Action - dobackupfiles
    *   start to handle dobackupfiles function
    *   need confirm to dobackupfiles
    ************************************************************/	
    function dobackupfiles(){
       	Ext.MessageBox.confirm(ttMessageTitle, ttconfirmbackupfiles + ' ?' , dobackupfiles2);	
    }     

    // History buton click handler. It submits the request and displays the response using history dialog
    function dobackupfiles2(btn) {
        if(btn == 'yes') {
            action = "dobackupfiles";
            grid.getGridEl().mask(ttBackupingfiles + '...');
            conn.request({
                url: 'listPath.cgi',
                method: 'GET',
                params: {"action": action,"lang": ttlang},
                success: function(responseObject) {
                    Ext.MessageBox.alert('Confirmation', responseObject.responseText);
                    grid.getGridEl().unmask(true);
                },
                failure: function() {
                    grid.getGridEl().unmask(true);
                    Ext.Msg.alert('Status', ttBackupingfilesError + '. '+ttReloadingApacheError+'.');
                }
            });
        }
    }
   /************************************************************
    * Action - delete
    *   start to handle delete function
    *   need confirm to delete
    ************************************************************/	
    function doDel(){
        var m = grid.getSelections();
        if(m.length > 0)
        {
        	Ext.MessageBox.confirm(ttMessageTitle, ttconfirmitemtodelete+'?' , doDel2);	
        }
        else
        {
        	Ext.MessageBox.alert(ttErrorTitle, ttselectonitemtodelete);
        }
    }     
      
    function doDel2(btn)
	{
       if(btn == 'yes')
       {	
			var m = grid.getSelections();
			var postname = "";
			var postpath = "";
	        for(var i = 0, len = m.length; i < len; i++){        		
				postid = "" + m[i].get("id") + "";
				postname = "" + m[i].get("name") + "";
				postpath = "" + m[i].get("path") + "";
				ds.remove(m[i]);								
	        }			
			var doaction = "delData";
            conn.request({
                url: 'listPath.cgi?action='+doaction+'&lang='+ttlang,
                method: 'POST',
                params: {"name":postname, "path":postpath, "id":postid},
                success: function(responseObject) {
                    var jsonData = Ext.util.JSON.decode(responseObject.responseText);
                    Ext.MessageBox.alert('Confirmation', jsonData.info);
                    grid.getGridEl().unmask(true);
                },
                failure: function() {
                    grid.getGridEl().unmask(true);
                    Ext.Msg.alert(ttErrorTitle, ttunabletodeletepath+' '+postname+' ('+postpath+').');
                }
            });

			ds.load({params:{start:0, limit:myPageSize}});
		}
	}
	
   /************************************************************
    *  Add an "clickoutside" event to a Grid.
    *     @param grid {Ext.grid.Grid} The grid to add a clickoutside event to.
    *     The handler is passed the Event and the Grid.
    ************************************************************/	
    function addClickOutsideEvent(grid) {
    	if (!grid.events.clickoutside) {
	    	grid.addEvents({"clickoutside": true});
	    }
	    if (!Ext.grid.Grid.prototype.handleClickOutside) {
	    	Ext.grid.Grid.override({
	    		handleClickOutside: function(e) {
		            var p = Ext.get(e.getTarget()).findParent(".x-grid-container");
		            if (p != this.container.dom) {
				        this.fireEvent("clickoutside", e, grid);
		            }
	    		}
	    	});
	    }
        Ext.get(document.body).on("click", grid.handleClickOutside, grid);
    }

   /************************************************************
    * Create a new dialog - reuse by create and edit part
    ************************************************************/    
    function createNewDialog(dialogName) {
        var thisDialog = new Ext.LayoutDialog(dialogName, {
                modal:true,
                autoTabs:true,
                proxyDrag:true,
                resizable:false,
                width: 480,
                height: 302,
                shadow:true,
				center: {
                    autoScroll: true,
                    tabPosition: 'top',
                    closeOnTab: true,
                    alwaysShowTabs: false
                }
        });
        thisDialog.addKeyListener(27, thisDialog.hide, thisDialog); 
        thisDialog.addButton(ttCancel, function() {thisDialog.hide();});
        
        return thisDialog;
    };
    
 
	
	 
   /************************************************************
    * Action - add
    *   start to handle add function
    *   new page appear and allow to submit
    ************************************************************/
    
   /************************************************************
    *  To create add new path dialog now....
    ************************************************************/   
    function doAdd(){
        var aAddInstanceDlg;
        
        if (!aAddInstanceDlg) {
            aAddInstanceDlg = createNewDialog("a-addInstance-dlg");       
            aAddInstanceDlg.addButton(ttReset, resetForm, aAddInstanceDlg);
            aAddInstanceDlg.addButton(ttSave, function() {       

		    	
		    	// submit now... all the form information are submit to the server
		    	// handle response after that...
		    	if (form_instance_create.isValid()) {
				    form_instance_create.submit({
						waitMsg:ttunabletodeletepath+' ...',
						reset: false,
						failure: function(form_instance_create, action) {
						    Ext.MessageBox.alert(ttErrorTitle, action.result.errorInfo);
						},
						success: function(form_instance_create, action) {
						    Ext.MessageBox.alert('Confirmation', action.result.info);
						    aAddInstanceDlg.hide();
						    ds.load({params:{start:0, limit:myPageSize}});
						}
					});					
				}else{
					Ext.MessageBox.alert(ttErrorTitle, tterrorformnewpath+'.');
				}	    	
		    });

			var layout = aAddInstanceDlg.getLayout();
            layout.beginUpdate();
            layout.add('center', new Ext.ContentPanel('a-addInstance-inner', {title: tttitlecreatpath}));
            layout.endUpdate(); 
            
            aAddInstanceDlg.show();
	    };        
	};


   /************************************************************
    * Form information - pop-up dialog
	* turn on validation errors beside the field globally
	************************************************************/
   	Ext.form.Field.prototype.msgTarget = 'side';
   	Ext.form.Field.prototype.height = 20;
	Ext.form.Field.prototype.fieldClass = 'text-field-default';
	Ext.form.Field.prototype.focusClass = 'text-field-focus';
	Ext.form.Field.prototype.invalidClass = 'text-field-invalid';

    /************************************************************
    * Create new form to hold user enter information
    * This form is used to create new instance
    ************************************************************/  
    var name_tf = new Ext.form.TextField({
            fieldLabel: ttName,
            name: 'name',
            allowBlank:false
    });
    var path_tf = new Ext.form.TextField({
		fieldLabel: ttPath,
		name: 'path',
		allowBlank:false
	});
 
    var form_instance_create = new Ext.form.Form({
        labelAlign: 'right',
        url:'listPath.cgi?action=createPath'+'&lang='+ttlang
    });

    form_instance_create.column({width: 430, labelWidth:120, style:'margin-left:8px;margin-top:8px'});
    form_instance_create.fieldset(
        {id:'desc', legend:ttpleasefillfields},
        name_tf,
        path_tf
	);
	
    form_instance_create.applyIfToFields({width:255});
    form_instance_create.render('a-addInstance-form');
    form_instance_create.end();
    
    resetForm = function() {
		name_tf.setValue('');
		path_tf.setValue('');
	};

});

if(Ext.MessageBox){
   Ext.MessageBox.buttonText = {
	  ok     : ttOK,
	  cancel : ttCancel,
	  yes    : ttYes,
	  no     : ttNo
   };
}


EndOfFile

# normal part
print <<EndOfFile;
    </script>
    <link rel="stylesheet" type="text/css" href="/scripts/extjs/resources/css/ext-all.css"><!-- AJAX stuff -->
    <link rel="stylesheet" type="text/css" href="/scripts/extjs/resources/css/xtheme-aero.css"><!-- Same shine theme Synology is using -->	</head>

    <!-- Include Ext stylesheets here: -->
    <STYLE type="text/css">
.header {
    width: 100%;
    height: 70px;
    background-color: #A9BFD3;
}
.separ {
    width: 100%;
    height: 25px;
    background: url(images/bb.png) repeat;
}
.zone {
    margin-top: 10px;
}
.neuf {
    background-color: #DEECFD;
}
	</STYLE>

EndOfFile

print "    <title>".trans("SynoNeuf configuration page")."</title>\n";


print '</head>';
print '<body>';
print '<div class="content"> ';
print '<div class="header"><img src="images/mclogo.png" /></div>';
print '<div class="separ"></div>';
print '<H1 class="neuf">&nbsp;&nbsp;&nbsp;'.trans("Application configuration").'</H1>'."\n";

print <<'EndOfFile';
<!-- Start call JS to get table list -->
<div id="grid-panel" style="width:100%;height:290px;" >
    <div id="editor-grid"></div>
</div>
<!-- end call JS to get table list -->
<br>
<!-- Add Path Dialog -->
<div id="a-addInstance-dlg" style="visibility:hidden;">

EndOfFile

print '	<div class="x-dlg-hd">'.trans("Add New Path").'</div>';

print <<'EndOfFile';
	<div class="x-dlg-bd">
	    <div id="a-addInstance-inner" class="x-layout-inactive-content">
	    		<div id="a-addInstance-form"></div>
	    </div>
	</div>
</div>

<br>
<div class="zone">
    <iframe width="50%" height="25%" src="http://synoneuf.mistertom.info/synoneuf.php" />
</div>

</div>
</body>

</html>

EndOfFile


